<template>
  <div class="particleConversionBox"></div>
</template>

<script>
import CONTANT from "@/lib/contant.js";
import * as THREE from "@/static/three.module.js";
import { TWEEN } from "@/static/libs/tween.module.min.js";
import { PLYLoader } from "@/static/loaders/PLYLoader.js";
import { OrbitControls } from "@/static/controls/OrbitControls.js";

export default {
  mounted() {
    //一些初始化
    var scene = new THREE.Scene();
    var camera = new THREE.PerspectiveCamera(
      45,
      (window.innerWidth - CONTANT.LEFT_WIDTH) /
        (window.innerHeight - CONTANT.TOP_HEIGHT),
      0.1,
      2000
    );
    camera.position.x = 600;
    camera.lookAt(new THREE.Vector3(0, -2, 0));

    var webGLRenderer = new THREE.WebGLRenderer();
    webGLRenderer.setClearColor(new THREE.Color(0x000, 0.0));
    webGLRenderer.setSize(
      window.innerWidth - CONTANT.LEFT_WIDTH,
      window.innerHeight - CONTANT.TOP_HEIGHT
    );
    webGLRenderer.shadowMap.enabled = true;

    var controls;
    controls = new OrbitControls(camera, webGLRenderer.domElement);
    controls.minDistance = 500;
    controls.maxDistance = 6000;
    controls.update();

    //光源
    var spotLight = new THREE.SpotLight(0xffffff);
    spotLight.position.set(20, 20, 20);
    scene.add(spotLight);

    document
      .querySelector(".particleConversionBox")
      .appendChild(webGLRenderer.domElement);

    //获取纹理
    var material = new THREE.PointsMaterial({
      color: 0xffffff,
      size: 10,
      opacity: 1,
      transparent: true,
      blending: THREE.AdditiveBlending,
      map: generateSprite(),
    });

    var arrTrans = [];
    var arrTransTo = [];
    var tween1 = new TWEEN.Tween({ pos: 0 }).to({ pos: 1 }, 4000);
    tween1.easing(TWEEN.Easing.Sinusoidal.InOut);
    tween1.onUpdate(onUpdate1);
    function onUpdate1() {
      var pos = this._object.pos;
      for (var i = 0; i < arrEarth.length; i++) {
        arrTrans[i] += (arrEarth[i] - arrTrans[i]) * pos;
      }
      pointInit.geometry.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(arrTrans, 3)
      );
      arrTrans.sortParticles = true;
    }

    var tween2 = new TWEEN.Tween({ pos: 0 }).to({ pos: 1 }, 4000);
    tween2.easing(TWEEN.Easing.Sinusoidal.InOut);
    tween2.onUpdate(onUpdate2);
    //tween2.onComplete(onComplete2);
    function onUpdate2() {
      var pos = this._object.pos;
      for (var i = 0; i < arrTransTo.length; i++) {
        arrTrans[i] += (arrTransTo[i] - arrTrans[i]) * pos;
      }
      pointInit.geometry.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(arrTrans, 3)
      );
      arrTrans.sortParticles = true;
    }
    //function onComplete2() {}

    var tween3 = new TWEEN.Tween({ pos: 0 }).to({ pos: 1 }, 4000);
    tween3.easing(TWEEN.Easing.Sinusoidal.InOut);
    tween3.onUpdate(onUpdate3);
    function onUpdate3() {
      var pos = this._object.pos;
      for (var i = 0; i < arrWhale.length; i++) {
        arrTrans[i] += (arrWhale[i] - arrTrans[i]) * pos;
      }
      pointInit.geometry.setAttribute(
        "position",
        new THREE.Float32BufferAttribute(arrTrans, 3)
      );
      arrTrans.sortParticles = true;
    }

    setTimeout(() => {
      var i;
      arrTrans = [];
      for (i = 0; i < arrInit.length; i++) {
        arrTrans.push(arrInit[i]);
      }
      for (i = arrInit.length; i < arrEarth.length; i++) {
        arrTrans.push((Math.random() - 0.5) * 1000);
      }
      tween1.start();
    }, 2000);

    setTimeout(() => {
      var i;
      arrTransTo = [];
      for (i = 0; i < arrTrans.length; i++) {
        arrTransTo.push((Math.random() - 0.5) * 1000);
      }
      tween2.start();
    }, 8000);

    setTimeout(() => {
      var i;
      arrTrans = [];
      for (i = 0; i < arrTransTo.length; i++) {
        arrTrans.push(arrTransTo[i]);
      }
      for (i = arrTransTo.length; i < arrWhale.length; i++) {
        arrTrans.push((Math.random() - 0.5) * 1000);
      }
      tween3.start();
    }, 14000);

    //随机生成一些点
    var pointInit = new THREE.Object3D();
    var arrInit;
    var geometry = new THREE.BufferGeometry();
    var randomPoints = [];
    for (var i = 0; i < 15000; i++) {
      randomPoints.push((Math.random() - 0.5) * 1000);
    }
    var vertices = new Float32Array(randomPoints);
    geometry.setAttribute("position", new THREE.BufferAttribute(vertices, 3));
    pointInit = new THREE.Points(geometry, material);
    arrInit = pointInit.geometry.attributes.position.array;
    pointInit.sortParticles = true;
    scene.add(pointInit);

    //加载第一个模型
    var pointEarth = new THREE.Object3D();
    var arrEarth;
    var loader = new PLYLoader();
    loader.load(CONTANT.URLPATH + "/models/ply/earth.ply", function (geometry) {
      pointEarth = new THREE.Points(geometry, material);
      arrEarth = pointEarth.geometry.attributes.position.array;
      pointEarth.sortParticles = true;
    });

    //加载第二个模型
    var pointWhale = new THREE.Object3D();
    var arrWhale;
    loader.load(CONTANT.URLPATH + "/models/ply/whale.ply", function (geometry) {
      pointWhale = new THREE.Points(geometry, material);
      arrWhale = pointWhale.geometry.attributes.position.array;
      pointWhale.sortParticles = true;
    });

    //获取纹理
    function generateSprite() {
      var canvas = document.createElement("canvas");
      canvas.width = 16;
      canvas.height = 16;

      var context = canvas.getContext("2d");
      var gradient = context.createRadialGradient(
        canvas.width / 2,
        canvas.height / 2,
        0,
        canvas.width / 2,
        canvas.height / 2,
        canvas.width / 2
      );
      gradient.addColorStop(0, "rgba(255,255,255,1)");
      gradient.addColorStop(0.2, "rgba(0,255,255,1)");
      gradient.addColorStop(0.4, "rgba(0,0,64,1)");
      gradient.addColorStop(1, "rgba(0,0,0,1)");

      context.fillStyle = gradient;
      context.fillRect(0, 0, canvas.width, canvas.height);

      var texture = new THREE.Texture(canvas);
      texture.needsUpdate = true;
      return texture;
    }

    //渲染
    function render() {
      TWEEN.update();
      requestAnimationFrame(render);

      const time = Date.now() * 0.001;
      pointInit.rotation.y = -(time * 0.25);

      webGLRenderer.render(scene, camera);
    }
    render();
  },
};
</script>

<style>
.particleConversionBox {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
}
</style>
